#pragma once

#include <functional>
#include <string>
#include <system_error>

#include "helper/sqlite/ActionResult.h"
#include "helper/sqlite/ExecutionResult.h"
#include "helper/sqlite/QueryResult.h"


namespace helper {
namespace sqlite {

class IDB;

class Statement {
public:
  Statement(const IDB * db = nullptr, void * stmt = nullptr);
  ~Statement();

  Statement(Statement && other);
  Statement & operator= (Statement && other);

  Statement(const Statement &) = delete;
  Statement & operator= (const Statement & ) = delete;

public:
  std::error_code reset();

  inline std::error_code prepareInput(const std::function<std::error_code (Statement & stmt)> & fbind){
    return fbind(*this);
  }


  ActionResult action();

  ExecutionResult execute();

  QueryResult query() const;
  QueryResult queryNoNext() const;


public:
  std::error_code clearBindings();

  //note lifetime of text: alive in executing
  std::error_code textBind(int index, const char * text, int len) ;
  //note lifetime of text: alive in executing
  std::error_code textBind(int index, const std::string & text);

  //note lifetime of binary: alive in executing
  std::error_code binaryBind(int index, const void * binary, int len);
  //note lifetime of binary: alive in executing
  std::error_code binaryBind(int index, const std::string & binary);

  //note lifetime of binary: alive in executing
  std::error_code binary64Bind(int index, const void * binary, int64_t len);
  //note lifetime of binary: alive in executing
  std::error_code binary64Bind(int index, const std::string & binary);

  std::error_code intBind(int index, const int value);
  std::error_code int64Bind(int index, const int64_t value);

  std::error_code doubleBind(int index, const double value);

  std::error_code nullBind(int index) ;

  std::error_code zeroBinaryBind(int index, int len);
  std::error_code zeroBinary64Bind(int index, int64_t len);

protected:
  std::error_code step();


private:
  void __moveImpl(Statement & other);
private:
  const IDB * _db;
  void * _stmt;
};

}//namespace sqlite
}//namespace helper
